#include "pendientes.h"
#include <iostream>
#include <sstream> // define el tipo ostringstream
#include <string>
#include <cassert> // define assert
#include <cstdlib> // define rand

using namespace std;

#define RUNTEST(t){ cerr << "Corriendo test " << #t << "..."; t (); cerr << " ok!" << endl; }

void asegurar(const Pendientes& p, string s){
	ostringstream out;
	p.mostrar(out);
	string t = out.str();
	if(s != t){
		cerr << s << " != " << t << endl;
		assert(false);
	}
}

void asegurar(const Lista<vivienda>& l, string s){
    ostringstream out;
    l.mostrarLista(out);
    string t = out.str();
    if(s != t){
        cerr << s << " != " << t << endl;
        assert(false);
    }
}

void testEncolar(){
	Catalogo c;
	for(int i=0;i<5;i++){
		Multiconj_materiales v;
		int materiales = 1 + rand()%10;
		for(int j=0; j<materiales;j++){
			v.agregar(rand()%10,1 + rand()%10);
		}
		c.agregarVivienda(v);
	}
	
	Pendientes p(c,c.cantMateriales());
	asegurar(p,"[]");
	p.encolar(1);
	asegurar(p,"[1]");
	p.encolar(0);
	asegurar(p,"[1,0]");
	p.encolar(2);
	asegurar(p,"[1,0,2]");
	p.encolar(2);
	asegurar(p,"[1,0,2,2]");
	p.encolar(2);
	asegurar(p,"[1,0,2,2,2]");
	p.encolar(1);
	asegurar(p,"[1,0,2,2,2,1]");
	p.encolar(3);
	asegurar(p,"[1,0,2,2,2,1,3]");
	p.encolar(3);
	asegurar(p,"[1,0,2,2,2,1,3,3]");
	p.encolar(1);
	asegurar(p,"[1,0,2,2,2,1,3,3,1]");
	p.encolar(2);
	asegurar(p,"[1,0,2,2,2,1,3,3,1,2]");
}

void testDesencolar(){
	Catalogo c;
	for(int i=0;i<5;i++){
		Multiconj_materiales v;
		int materiales = 1 + rand()%10;
		for(int j=0; j<materiales;j++){
			v.agregar(j,1 + rand()%10);
		}
		c.agregarVivienda(v);
	}

	Pendientes p(c,c.cantMateriales());
	asegurar(p,"[]");
	p.encolar(1);
	asegurar(p,"[1]");
	p.desencolar();
	asegurar(p,"[]");
	p.encolar(0);
	asegurar(p,"[0]");
	p.encolar(2);
	asegurar(p,"[0,2]");
	p.desencolar();
	asegurar(p,"[2]");
	p.encolar(2);
	asegurar(p,"[2,2]");
	p.encolar(2);
	asegurar(p,"[2,2,2]");
	p.desencolar();
	asegurar(p,"[2,2]");
	p.encolar(1);
	asegurar(p,"[2,2,1]");
	p.encolar(3);
	asegurar(p,"[2,2,1,3]");
	p.encolar(3);
	asegurar(p,"[2,2,1,3,3]");
	p.encolar(1);
	asegurar(p,"[2,2,1,3,3,1]");
	p.encolar(2);
	asegurar(p,"[2,2,1,3,3,1,2]");
}

void testCola(){
	Catalogo c;
	for(int i=0;i<5;i++){
		Multiconj_materiales v;
		int materiales = 1 + rand()%10;
		for(int j=0; j<materiales;j++){
			v.agregar(rand()%10,1 + rand()%10);
		}
		c.agregarVivienda(v);
	}
	
	Pendientes p(c,c.cantMateriales());
	asegurar(p.cola(),"[]");
	p.encolar(1);
	asegurar(p.cola(),"[1]");
	p.encolar(0);
	asegurar(p.cola(),"[1,0]");
	p.encolar(2);
	asegurar(p.cola(),"[1,0,2]");
	p.encolar(2);
	asegurar(p.cola(),"[1,0,2,2]");
	p.encolar(2);
	asegurar(p.cola(),"[1,0,2,2,2]");
	p.encolar(1);
	asegurar(p.cola(),"[1,0,2,2,2,1]");
	p.encolar(3);
	asegurar(p.cola(),"[1,0,2,2,2,1,3]");
	p.encolar(3);
	asegurar(p.cola(),"[1,0,2,2,2,1,3,3]");
	p.encolar(1);
	asegurar(p.cola(),"[1,0,2,2,2,1,3,3,1]");
	p.encolar(2);
	asegurar(p.cola(),"[1,0,2,2,2,1,3,3,1,2]");
}

void testEsta(){
	Catalogo c;
	for(int i=0;i<5;i++){
		Multiconj_materiales v;
		int materiales = 1 + rand()%10;
		for(int j=0; j<materiales;j++){
			v.agregar(rand()%10,1 + rand()%10);
		}
		c.agregarVivienda(v);
	}
	
	Pendientes p(c,c.cantMateriales());
	p.encolar(1);
	p.encolar(0);
	p.encolar(2);
	p.encolar(2);
	p.encolar(2);
	p.encolar(1);
	p.encolar(3);
	p.encolar(3);
	p.encolar(1);
	p.encolar(2);
	assert(p.esta(0));
	assert(p.esta(1));
	assert(p.esta(2));
	assert(p.esta(3));
	assert(!p.esta(4));
	assert(!p.esta(5));
}

void testHayPendiente(){
	Catalogo c;
	for(int i=0;i<5;i++){
		Multiconj_materiales v;
		int materiales = 1 + rand()%10;
		for(int j=0; j<materiales;j++){
			v.agregar(rand()%10,1 + rand()%10);
		}
		c.agregarVivienda(v);
	}
	
	Pendientes p(c,c.cantMateriales());
	assert(!p.hayPendiente());
	p.encolar(1);
	assert(p.hayPendiente());
	p.encolar(0);
	assert(p.hayPendiente());
}

void testPrimera(){
	Catalogo c;
	for(int i=0;i<5;i++){
		Multiconj_materiales v;
		int materiales = 1 + rand()%10;
		for(int j=0; j<materiales;j++){
			v.agregar(rand()%10,1 + rand()%10);
		}
		c.agregarVivienda(v);
	}
	
	Pendientes p(c,c.cantMateriales());
	p.encolar(1);
	assert(p.primera()==1);
	p.encolar(0);
	assert(p.primera()==1);
}

void testIterTieneProximo(){
	Catalogo c;
	for(int i=0;i<5;i++){
		Multiconj_materiales v;
		v.agregar(1,1+rand()%10);
		int materiales = rand()%10;
		for(int j=0; j<materiales;j++){
			v.agregar(rand()%10,1 + rand()%10);
		}
		c.agregarVivienda(v);
	}

	Pendientes p(c,c.cantMateriales());
	Pendientes::iterPendientes it(p,1);
	assert(!it.tieneProximo());
	p.encolar(1);
	it = Pendientes::iterPendientes(p,1);
	assert(it.tieneProximo());
	p.encolar(0);
	assert(it.tieneProximo());
	p.encolar(2);
	assert(it.tieneProximo());
	it.avanzar();
	assert(it.tieneProximo());
	it.avanzar();
	assert(it.tieneProximo());
	it.avanzar();
	assert(!it.tieneProximo());
	/*Pendientes::iterPendientes it2(p,1);
	while(it2.tieneProximo()){
		
	}*/
	
}

void testIterActualAvanzar(){
	Catalogo c;
	for(int i=0;i<5;i++){
		Multiconj_materiales v;
		v.agregar(1,rand()%10);
		int materiales = rand()%10;
		for(int j=0; j<materiales;j++){
			v.agregar(rand()%10,1 + rand()%10);
		}
		c.agregarVivienda(v);
	}

	Pendientes p(c,c.cantMateriales());
	p.encolar(1);
	Pendientes::iterPendientes it(p,1);
	assert(it.actual()==1);
	p.encolar(0);
	it.avanzar();
	assert(it.actual()==0);
	p.encolar(2);
	p.encolar(2);
	it.avanzar();
	assert(it.actual()==2);
	it.avanzar();
	assert(it.actual()==2);
}

void testIterEliminar(){
	Catalogo c;
	/*for(int i=0;i<5;i++){
		Multiconj_materiales v;
		v.agregar(1,1 + rand()%10);
		int materiales = rand()%10;
		for(int j=0; j<materiales;j++){
			v.agregar(rand()%10,1 + rand()%10);
		}
		c.agregarVivienda(v);
	}*/
	Multiconj_materiales v0;
		v0.agregar(0,1);
	Multiconj_materiales v1;
		v1.agregar(1,1);
	Multiconj_materiales v2;
		v2.agregar(2,1);
	c.agregarVivienda(v0);
	c.agregarVivienda(v1);
	c.agregarVivienda(v2);

	Pendientes p(c,c.cantMateriales());
	p.encolar(1);
	p.encolar(0);
	p.encolar(2);
	
	Pendientes::iterPendientes it=p.crearIterPendientes(1);
	it.eliminar();

	Pendientes::iterPendientes it2=p.crearIterPendientes(1);
	/*asegurar(p,"[1]");
	Pendientes::iterPendientes it2(p,1);
	asegurar(p,"[1]");
	it2.eliminar();*/
	/*asegurar(p,"[]");
	p.encolar(2);
	p.encolar(2);
	Pendientes::iterPendientes it3(p,1);*/
	/*p.encolar(2);
	p.encolar(1);
	p.encolar(3);
	p.encolar(3);
	p.encolar(1);
	p.encolar(2);*/
}

int main() {
	RUNTEST(testEncolar);
	RUNTEST(testDesencolar);
	RUNTEST(testCola);
	RUNTEST(testEsta);
	RUNTEST(testHayPendiente);
	RUNTEST(testPrimera);
	RUNTEST(testIterTieneProximo);
	RUNTEST(testIterActualAvanzar);
	RUNTEST(testIterEliminar);
	return 0;
}
